#include "bbh_outbuffer.h"

#include "bbh_include.h"

#define BUFFER_IS_FULL(_) (_->buf_len == _->max_len && _->buf_len == _->data_len)

/**
 * @brief 创建实例
 * 
 * @param max_len   消息最大长度
 * @param pptr      生成的实例
 * @return int      0成功
 */
int bbh_outbuffer_create(size_t max_len, bbh_outbuffer_t**pptr)
{
    struct bbh_outbuffer_s* p = (struct bbh_outbuffer_s*)malloc(sizeof(struct bbh_outbuffer_s));
    if (!p) {
        return -1;
    }
    memset(p, 0, sizeof(struct bbh_outbuffer_s));
    p->max_len = max_len;
    *pptr = p;
    return 0;
}

/**
 * @brief 扩大实例尺寸，但不能超过最大尺寸
 * 
 * @param _         实例
 * @param delta     要扩大的增量
 * @return int      0成功。>0 配置限制。<0 失败, 
 */
int bbh_outbuffer_extend(bbh_outbuffer_t*_, size_t delta)
{
//    printf("%zd 扩容增量 %zd\n", _->buf_len, delta);
    size_t d = _->max_len - _->buf_len;
    if (0 == d) {
        return 1;
    }
    if (d > delta) {
        _->buf = (char*)realloc(_->buf, _->buf_len + delta);
        _->buf_len += delta;
    } else {
        _->buf = (char*)realloc(_->buf, _->max_len);
        _->buf_len = _->max_len;
    }
    return _->buf ? 0 : -1;
}

/**
 * @brief   向实例写入数据
 * 
 * @param _         实例
 * @param data      写入的数据
 * @param len       写入的数据长度
 * @return int      0成功。>0 配置限制。<0 失败, 
 */
int bbh_outbuffer_write(bbh_outbuffer_t*_, const char*data, size_t len)
{
    int r;
    size_t n;

    if (BUFFER_IS_FULL(_)) {
        _->pending_count += len;
        return 1;
    }
    r = 0;
    // 现在有空间
    n = _->buf_len - _->data_len;
    if (len > n) {
        if ((r = bbh_outbuffer_extend(_, len - n)) < 0) {
            return r;
        }
        // 现有空间的长度
        n = _->buf_len - _->data_len;
        memcpy(_->buf + _->data_len, data, n);
        _->data_len += n;
        _->pending_count += len - n;
    } else {
        memcpy(_->buf + _->data_len, data, len);
        _->data_len += len;
    }
    return 0;
}

/**
 * @brief 格式化输出
 * 
 * @param _         实例
 * @param fmt       格式
 * @param args      格式需要的数据
 * @return int      0成功。>0 配置限制。<0 失败,
 */
int bbh_outbuffer_vprint(bbh_outbuffer_t*_, const char*fmt, va_list args)
{
    int r;
    int n;
     va_list ap;

    // 已经写满了
    if (BUFFER_IS_FULL(_)) {
        _->pending_count += 1;
        return 1;
    }

    va_copy(ap, args);

    // 现有空闲长度
    n = (int)(_->buf_len - _->data_len);
    r = vsnprintf(_->buf + _->data_len, n, fmt, args);
    if (r < 0) {
        return r;
    }
    // 没写完要扩容
    if (r > (int)n) {
        if ((r = bbh_outbuffer_extend(_, r - (int)n + 1)) < 0) {
            return r;
        }
        // 真实增加的长度
        n = (int)(_->buf_len - _->data_len);
        r = vsnprintf(_->buf + _->data_len, n, fmt, ap);
        va_end(ap);
        if (r < 0) {
            return r;
        }

        _->data_len += ((r > n) ? n : r);
        _->pending_count += ((r > n) ? (r - n) : 0);
    } else {
        _->data_len += r;
    }

    return r;
}

/**
 * @brief 格式化输出
 * 
 * @param _         实例
 * @param fmt       格式
 * @param ...       格式需要的数据
 * @return int      写入后实例数据的长度。<0 格式化失败
 */
int bbh_outbuffer_print(bbh_outbuffer_t*_, const char*fmt, ...)
{
    int r;
    va_list ap;
    va_start(ap, fmt);
    r = bbh_outbuffer_vprint(_, fmt, ap);
    va_end(ap);
    return r;
}

int bbh_outbuffer_strftime(bbh_outbuffer_t*_, const char*fmt, time_t sec)
{
    // 已经写满了
    if (BUFFER_IS_FULL(_)) {
        _->pending_count += 1;
        return 1;
    }
    size_t len;
    char   temp[256];
    len = strftime(temp, 256, fmt, localtime(&sec));
    if (0 == len) {
        len = strftime(temp, 256, "%F %T", localtime(&sec));
    }
    if (len) {
        return bbh_outbuffer_write(_, temp, len);
    }
    return 0;
}

void bbh_outbuffer_reset(bbh_outbuffer_t*_)
{
    _->data_len = 0;
}

void bbh_outbuffer_clear(bbh_outbuffer_t*_)
{
    if(_->buf) {
        free(_->buf);
    }
    memset(_, 0, sizeof(bbh_outbuffer_t));
}

/**
 * @brief 释放实例
 * 
 * @param _         实例
 */
void bbh_outbuffer_free(bbh_outbuffer_t*_)
{
    if (_->buf) {
        free(_->buf);
    }
    free(_);
}